# This is a sample Python script.

# Press ⌃R to execute it or replace it with your code.
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
import math

import cv2 as cv
import numpy as np
import point


def resize_img(image, height=1800):
    h, w = image.shape[:2]
    pro = height / h
    s_w = int(w * pro)
    s_h = int(height)
    size = (s_w, s_h)
    img = cv.resize(image, size)
    return img


def first_step(src):
    # 灰度
    gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    # 高斯平滑
    gray = cv.GaussianBlur(gray, (3, 3), sigmaX=5, sigmaY=5, borderType=cv.BORDER_DEFAULT)
    # 边缘检测
    gray = cv.Canny(gray, 25, 50, apertureSize=3, L2gradient=False)
    # 膨胀操作，尽量使边缘闭合
    kernel = np.ones((3, 3), np.uint8)
    gray = cv.dilate(gray, kernel, iterations=0)
    ret, thresh = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)
    contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
    lt_coordinate = True
    rt_coordinate = True
    lb_coordinate = True
    rb_coordinate = True
    point_dict = {}
    for contour in contours:
        hull = cv.convexHull(contour)
        epsilon = 0.02 * cv.arcLength(contour, True)
        approx = cv.approxPolyDP(hull, epsilon, True)
        if len(approx) == 4:
            currentArea = cv.contourArea(approx)
            if 2000 < currentArea < 4000:
                x, y, w, h = cv.boundingRect(approx)
                p = point.Point(x, y, w, h)
                # cv.rectangle(src, (x, y), (x + w, y + h), (0, 255, 0), 2)
                # if x <= 675:
                if x <= 500:
                    if y <= 900 and lt_coordinate:
                        point_dict['lt'] = p
                        lt_coordinate = False
                    elif lb_coordinate:
                        point_dict['lb'] = p
                        lb_coordinate = False
                elif x >= 800:
                    if y <= 900 and rt_coordinate:
                        point_dict['rt'] = p
                        rt_coordinate = False
                    elif rb_coordinate:
                        point_dict['rb'] = p
                        rb_coordinate = False

    # 确定四个角
    lt = point_dict['lt']
    lb = point_dict['lb']
    rt = point_dict['rt']
    rb = point_dict['rb']
    print(lt.x, lt.y, lt.w, lt.h)
    # cv.rectangle(src, (lt.x, lt.y), (lt.x + lt.w, lt.y + lt.h), (0, 0, 0), 2)
    # cv.rectangle(src, (lb.x, lb.y), (lb.x + lb.w, lb.y + lb.h), (0, 0, 0), 2)
    # cv.rectangle(src, (rt.x, rt.y), (rt.x + rt.w, rt.y + rt.h), (0, 0, 0), 2)
    # cv.rectangle(src, (rb.x, rb.y), (rb.x + rb.w, rb.y + rb.h), (0, 0, 0), 2)
    # cv.circle(src, (lt.x - 20, lt.y - 20), 5, (0, 255, 0), 2)
    # cv.circle(src, (lb.x, lb.y + lb.h), 5, (0, 255, 0), 2)
    # cv.circle(src, (rt.x + rt.w, rt.y), 5, (0, 255, 0), 2)
    # cv.circle(src, (rb.x + rb.w, rb.y + rb.w), 5, (0, 255, 0), 2)
    cv.circle(src, (lt.x - 20, lt.y - 20), 5, (0, 255, 0), 2)
    cv.circle(src, (lb.x - 20, lb.y + lb.h + 30), 5, (0, 255, 0), 2)
    cv.circle(src, (rt.x + 30 + rt.w, rt.y - 20), 5, (0, 255, 0), 2)
    cv.circle(src, (rb.x + 30 + rb.w, rb.y + rb.w + 30), 5, (0, 255, 0), 2)

    return point.Point(lt.x - 20, lt.y - 20, 0, 0), \
           point.Point(lb.x - 20, lb.y + lb.h + 30, 0, 0), \
           point.Point(rt.x + 30 + rt.w, rt.y - 20, 0, 0), \
           point.Point(rb.x + 30 + rb.w, rb.y + rb.w + 30, 0, 0)


# 四边形顶点排序，[top-left, top-right, bottom-right, bottom-left]
def orderPoints(lt, lb, rt, rb):
    rect = np.zeros((4, 2), dtype="float32")
    rect[0] = [lt.x, lt.y]
    rect[1] = [rt.x, rt.y]
    rect[3] = [lb.x, lb.y]
    rect[2] = [rb.x, rb.y]
    return rect


# 计算长宽
def pointDistance(a, b):
    return int(np.sqrt(np.sum(np.square(a - b))))


# 透视变换
def warpImage(image, box):
    w, h = pointDistance(box[0], box[1]), \
           pointDistance(box[1], box[2])
    dst_rect = np.array([[0, 0],
                         [w - 1, 0],
                         [w - 1, h - 1],
                         [0, h - 1]], dtype='float32')
    M = cv.getPerspectiveTransform(box, dst_rect)
    warped = cv.warpPerspective(image, M, (w, h))
    return warped


def adaPoint(box, pro):
    box_pro = box
    if pro != 1.0:
        box_pro = box / pro
    box_pro = np.trunc(box_pro)
    return box_pro


path = '/Users/wanggh/Desktop/a.jpeg'
# path = '/Users/wanggh/Desktop/b.jpeg'
# path = '/Users/wanggh/Desktop/c.jpeg'
# path = '/Users/wanggh/Desktop/d.jpeg'
# path = '/Users/wanggh/Desktop/e.jpeg'
# path = '/Users/wanggh/Desktop/original.jpeg'
# path = '/Users/wanggh/Desktop/b.jpeg'
src = cv.imread(path)
src = resize_img(src)
lt, lb, rt, rb = first_step(src)

# cv.line(src, (lt.x, lt.y), (lb.x, lb.y), (0, 0, 255), 2)
# cv.line(src, (lt.x, lt.y), (rt.x, rt.y), (0, 0, 255), 2)
# cv.line(src, (lb.x, lb.y), (rb.x, rb.y), (0, 0, 255), 2)
# cv.line(src, (rt.x, rt.y), (rb.x, rb.y), (0, 0, 255), 2)
boxes = orderPoints(lt, lb, rt, rb)
# 透视变化
warped = warpImage(src, boxes)
#
# # 灰度
gray = cv.cvtColor(warped, cv.COLOR_BGR2GRAY)
# 高斯平滑
# warped = cv.GaussianBlur(gray, (3, 3), sigmaX=5, sigmaY=5, borderType=cv.BORDER_DEFAULT)
binary = cv.medianBlur(gray, 1)
ret, thresh = cv.threshold(binary, 127, 255, cv.THRESH_BINARY)

cv.imshow("test", thresh)
cv.waitKey(0)
cv.destroyAllWindows()
